﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using RssReader.DataModel;
using RssReader.FeedProvider;
using RssReader.FeedsProvider;
using RssReader.Storage;
using Windows.Storage;
using Windows.Web.Syndication;
using Item = RssReader.FeedProvider.Item;

namespace RssReader.Feeds
{
    public class CategoryHelper
    {
        private readonly IFeedProvider _feedProvider;
        readonly LocalSettings _localSettings = new LocalSettings();
        private const string CategorySettingsKey = "categorySettings";
        static private ConcurrentDictionary<string, object> _sessionState = new ConcurrentDictionary<string, object>();
        public CategoryHelper()
        {
            _feedProvider = new RssFeedProvider();
        }

        public List<Category> Categories = new List<Category>();

        public async Task<List<Category>> Get_all_categories()
        {
            Get_categories_from_composite_settings(false);

            await Get_all_items_in_category();
            return Categories;
        }


        public async Task<IList<Item>> Get_all_blog_posts_from_shown_categories()
        {
            var categories = await Get_all_categories();

            var items = new List<Item>();
            foreach (var category in categories)
            {
                //TODO Move maxItems to Settings
                items.AddRange(category.Feed.Items.Where(item => !string.IsNullOrEmpty(item.Image_path)).Take(10));
            }

            return items;
        }

        public async Task<IList<Item>> Search_all_blog_posts(string searchQueryText)
        {
            var categories = await Get_all_categories();

            var items = new List<Item>();
            foreach (var category in categories)
            {
                items.AddRange(category.Feed.Items.Where(item => item.Title.ToLower().Contains(searchQueryText.ToLower()) || item.Description.ToLower().Contains(searchQueryText.ToLower())));
            }

            return items;
        }

        public void Get_categories_from_composite_settings(bool getAllCategories)
        {
            var compositeKeyValuePair = _localSettings.Get_composite_key_value_pair(CategorySettingsKey);

            if (compositeKeyValuePair == null)
                Get_sample_categories_and_store_in_settings();

            compositeKeyValuePair = _localSettings.Get_composite_key_value_pair(CategorySettingsKey);

            if (compositeKeyValuePair != null)
            {
                Categories = new List<Category>();
                foreach (var key in compositeKeyValuePair.Keys)
                {
                    string url = compositeKeyValuePair[key].ToString().Split(new[]{'|'})[0];
                    string visible = compositeKeyValuePair[key].ToString().Split(new[]{'|'})[1];
                    bool isVisible = Convert.ToBoolean(visible);

                    var category = new Category {Name = key, Url = url, Visible = isVisible};
                    if (getAllCategories)
                    {
                        Categories.Add(category);
                    }
                    else if (isVisible)
                    {
                        Categories.Add(category);
                    }
                }
            }
        }

        private async Task Get_all_items_in_category()
        {
            foreach (var category in Categories.Where(id => id.Visible))
            {
                try
                {
                    if (!_sessionState.ContainsKey(category.Name))
                    {
                        //TODO Move maxItems to Settings
                        category.Feed = await _feedProvider.Get_feed(category.Url, category.Name, 10, category);
                        _sessionState[category.Name] = category.Feed;
                    }
                    else
                    {
                        category.Feed = (Feed) _sessionState[category.Name];
                    }
                        
                }
                catch (Exception)
                {
                }
            }
        }

        public async Task<List<Category>> Get_all_categories(string url)
        {
            Categories = new List<Category>();
            var feed = await _feedProvider.Syndication_feed(url,string.Empty);
            Get_all_item_categories_from_feed(url, feed);
            await Fill_categories_with_their_items(feed);
            Remove_categories_with_no_items();
            return Categories;
        }

        private void Remove_categories_with_no_items()
        {
            var filteredCategories = new List<Category>();
            foreach (var category in Categories)
            {
                if (category.Feed != null && category.Feed.Items.Count > 0)filteredCategories.Add(category);
            }

            Categories = filteredCategories;
        }

        private async Task Fill_categories_with_their_items(SyndicationFeed feed)
        {
            foreach (Category category in Categories.Take(10))
            {
                Func<SyndicationItem, string, bool> itemHasCategory = (item, categoryName) => item.Categories.Any(syndicationCategory => syndicationCategory.NodeValue.ToLower() == categoryName.ToLower());

                var syndicationItems = feed.Items.Where(item => itemHasCategory(item,category.Name)).ToList();
                var newFeed = new Feed
                                  {
                                      
                                      TotalItems = syndicationItems.Count,
                                      Title = category.Name,
                                      Url = category.Url
                                  };
                _feedProvider.Convert_syndicationitem_to_feed_item(category,newFeed,syndicationItems);
                category.Feed = newFeed;
            }
        }

        private void Get_all_item_categories_from_feed(string url, SyndicationFeed feed)
        {
            foreach (SyndicationItem syndicationItem in feed.Items)
            {
                foreach (SyndicationCategory syndicationCategory in syndicationItem.Categories)
                {
                    var categoryName = syndicationCategory.NodeValue;
                    if (Categories.FirstOrDefault(category => category.Name.ToLower() == categoryName.ToLower()) == null)
                    {
                        Categories.Add(new Category {Name = categoryName, Url = url});
                    }
                }
            }
        }

        public void Put_categories(List<Category> categories)
        {
            this.Write_categories_to_settings(categories);
        }

        public async Task Write_categories_to_settings(List<Category> categories)
        {
            var compositeKeyValue = new ApplicationDataCompositeValue();

            foreach (var category in categories)
            {
                compositeKeyValue.Add(new KeyValuePair<string, object>(category.Name, string.Format("{0}|{1}", category.Url,category.Visible)));
            }

            _localSettings.Remove_setting(CategorySettingsKey);
            _localSettings.Store_composite_value(CategorySettingsKey, compositeKeyValue);
        }

        private void Get_sample_categories_and_store_in_settings()
        {
            var compositeKeyValue = Create_sample_categories();
            _localSettings.Store_composite_value(CategorySettingsKey,compositeKeyValue);
        }

        private ApplicationDataCompositeValue Create_sample_categories()
        {
            var composite = new ApplicationDataCompositeValue();
            composite["Engadget"] = "http://www.engadget.com/rss.xml|true";

            composite["Yahoo News"] = "http://news.yahoo.com/rss|true";

            return composite;
        }
    }
}
